﻿#define DEBUG
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Wangzeran.CodeMaker.Core.Config;
using Wangzeran.CodeMaker.Core.DB;
using Wangzeran.CodeMaker.Core.Files;
using Wangzeran.CodeMaker.Core.Model;
using Wangzeran.CodeMaker.Core.Template;
using Wangzeran.CodeMaker.GUI.Codes;
using Wangzeran.CodeMaker.GUI.Modal;
using Wangzeran.CodeMaker.GUI.Utils;
using System.IO;
using System.Diagnostics;

namespace Wangzeran.CodeMaker.GUI.Forms
{
    /// <summary>
    /// 主窗体
    /// </summary>
    public partial class MainForm : Form
    {
        /// <summary>
        /// 操作XML文件
        /// </summary>
        private XmlMgt opXml = new XmlMgt();
        /// <summary>
        /// 数据库架构操作
        /// </summary>
        IDBSchema opSchema = null;
        /// <summary>
        /// 当前数据库的表
        /// </summary>
        private IDictionary<string, TableModal> dicTables = new Dictionary<string, TableModal>();
        /// <summary>
        /// 模板语言类型
        /// </summary>
        private string m_Language = null;
        /// <summary>
        /// 出错内容
        /// </summary>
        private StringBuilder sbError = new StringBuilder();
        /// <summary>
        /// 最大工作线程数
        /// </summary>
        private const int MAX_WORKED_THREADS = 25;
        /// <summary>
        /// 最大线程
        /// </summary>
        private const int MAX_THREADS = 50;

        public MainForm()
        {
            try
            {
                InitializeComponent();

                CheckForIllegalCrossThreadCalls = false;

                ThreadPool.SetMaxThreads(MAX_WORKED_THREADS, MAX_THREADS);

                this.Text = "CodeMaker代码生成工具  v" +
                    Assembly.GetExecutingAssembly().GetName().Version.ToString(3);
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        /// <summary>
        /// 数据库配置窗体
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbtnDBSetting_Click(object sender, EventArgs e)
        {
            try
            {
                Form frm = new DBForm();
                frm.ShowDialog();

                DBModal dbModal = opXml.GetUseDatabase();
                if (dbModal != null
                    && DBPlugIns.Dbs.ContainsKey(dbModal.DatabaseType))
                {
                    AppSetting.DbPlugIn = DBPlugIns.Dbs[dbModal.DatabaseType];
                    AppSetting.DbPlugIn.DbUtility.ConnectionString = dbModal.ToString();
                    opSchema = AppSetting.DbPlugIn.DbSchema;
                }
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        /// <summary>
        /// 退出程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbtnExit_Click(object sender, EventArgs e)
        {
            Application.ExitThread();
        }

        /// <summary>
        /// 加载窗体
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            try
            {
                // 初始化配置文件
                ConfigFactory.InitConfig();

                // 读取当前使用的数据库配置
                DBModal dbModal = opXml.GetUseDatabase();
                if (dbModal != null
                    && DBPlugIns.Dbs.ContainsKey(dbModal.DatabaseType))
                {
                    AppSetting.DbPlugIn = DBPlugIns.Dbs[dbModal.DatabaseType];
                    AppSetting.DbPlugIn.DbUtility.ConnectionString = dbModal.ToString();
                    opSchema = AppSetting.DbPlugIn.DbSchema;
                }
                // 加载模板解析
                IDictionary<string, ITemplate> lstParseTemplates = TemplatePlugIns.Templates;
                foreach (string item in lstParseTemplates.Keys)
                {
                    cboParseTemplates.Items.Add(item);
                }
                if (cboParseTemplates.Items.Count > 0)
                {
                    cboParseTemplates.SelectedIndex = 0;
                }
                // 加载输出文件类型
                IDictionary<string, IFile> dicOutputFile = FilePlugIns.Files;
                IList<IFile> lstFiles = new List<IFile>();
                foreach (IFile file in dicOutputFile.Values)
                {
                    lstFiles.Add(file);
                }
                cboOutputFileExt.DataSource = lstFiles;
                cboOutputFileExt.DisplayMember = "FileDescription";
                cboOutputFileExt.ValueMember = "FileExt";
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }
        /// <summary>
        /// 加载数据库
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboDatabase_DropDown(object sender, EventArgs e)
        {
            try
            {
                if (AppSetting.DbPlugIn != null
                        && cboDatabase.Items.Count == 0)
                {
                    cboDatabase.Items.Clear();

                    if (opSchema == null)
                    {
                        return;
                    }
                    IDictionary<string, DatabaseModal> lstDatabase = opSchema.GetDatabases();
                    foreach (DatabaseModal database in lstDatabase.Values)
                    {
                        cboDatabase.Items.Add(database.DatabaseName);
                    }

                    cboDatabase.SelectedIndex = -1;
                }
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        /// <summary>
        /// 加载表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboDatabase_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (AppSetting.DbPlugIn != null
                        && cboDatabase.SelectedIndex > -1)
                {
                    cklstTables.Items.Clear();
                    dicTables.Clear();

                    if (opSchema == null)
                    {
                        return;
                    }
                    // 只获取表名
                    IList<string> lstTables = opSchema.GetTableNames(cboDatabase.Text.Trim());
                    foreach (string tableName in lstTables)
                    {
                        cklstTables.Items.Add(tableName);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        /// <summary>
        /// 模板管理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbtnTemplates_Click(object sender, EventArgs e)
        {
            try
            {
                Form frm = new TemplateForm();
                frm.ShowDialog();
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        /// <summary>
        /// 选择要生成代码的目录
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelectedGenerateFolder_Click(object sender, EventArgs e)
        {
            try
            {
                dlgTarget.Description = "请选择生成目标文件的目录";
                if (DialogResult.OK == dlgTarget.ShowDialog())
                {
                    txtGenerateFolder.Text = dlgTarget.SelectedPath;
                }
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        private string m_TargetPath = null;
        private string m_TemplatePath = null;
        private IFile m_OutputFile = null;
        private ITemplate m_Template = null;
        private int m_CurrentCount = 0;

        /// <summary>
        /// 检查是否可以生成
        /// </summary>
        /// <returns></returns>
        private bool CheckToGenerate()
        {
            try
            {
                if (cboTemplates.SelectedIndex == -1)
                {
                    MessageHelper.ShowWarning("提示", "请选择模板");
                    return false;
                }
                if (cboParseTemplates.SelectedIndex == -1)
                {
                    MessageHelper.ShowWarning("提示", "请选择模板解析方式");
                    return false;
                }
                if (cboDatabase.SelectedIndex == -1)
                {
                    MessageHelper.ShowWarning("提示", "请选择数据库");
                    return false;
                }
                if (cklstTables.CheckedItems.Count == 0)
                {
                    MessageHelper.ShowWarning("提示", "请选择表");
                    return false;
                }
                if (txtGenerateFolder.Text.Trim().Length == 0)
                {
                    MessageHelper.ShowWarning("提示", "请选择生成的目标路径");
                    return false;
                }
                if (cboOutputFileExt.SelectedIndex == -1)
                {
                    MessageHelper.ShowWarning("提示", "请选择生成的目标文件扩展名");
                    return false;
                }
                if (!radCSharp.Checked && !radJava.Checked)
                {
                    MessageHelper.ShowWarning("提示", "请选择语言类型");
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
                return false;
            }
        }


        /// <summary>
        /// 生成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbtnGenerate_Click(object sender, EventArgs e)
        {
            try
            {
                sbError.Remove(0, sbError.Length);

                Thread threadStatus = null;

                threadStatus = new Thread(delegate()
                {
                    tsslblStatus.Text = "等待";
                    tsslblStatus.ForeColor = Color.FromArgb(64, 64, 64);
                });
                threadStatus.Start();

                m_CurrentCount = 0;

                if (!CheckToGenerate())
                {
                    return;
                }

                threadStatus = new Thread(delegate()
                {
                    tsslblStatus.Text = "正在加载表信息……";
                    tsslblStatus.ForeColor = Color.Red;
                });
                threadStatus.Start();

                string[] tableNames = new string[cklstTables.CheckedItems.Count];
                cklstTables.CheckedItems.CopyTo(tableNames, 0);
                dicTables = opSchema.GetTables(cboDatabase.Text.Trim(), tableNames);

                threadStatus = new Thread(delegate()
                {
                    tsslblStatus.Text = "正在生成……";
                    tsslblStatus.ForeColor = Color.Red;
                });
                threadStatus.Start();

                // 数据类型
                string dataType = radCSharp.Checked ? radCSharp.Tag.ToString() : radJava.Tag.ToString();
                // 设置当前使用的数据类型
                DataTypeSupport.SetToUse(dataType);

                // 目标文件夹
                m_TargetPath = txtGenerateFolder.Text.Trim();
                // 模板文件路径
                m_TemplatePath = cboTemplates.SelectedValue.ToString();
                // 文件输出模板
                m_OutputFile = FilePlugIns.Files[cboOutputFileExt.SelectedValue.ToString()];
                // 模板
                m_Template = TemplatePlugIns.Templates[cboParseTemplates.Text];
                // 文件总数和计时器
                int totalCount = cklstTables.CheckedItems.Count;
                tsslblTotal.Text = totalCount.ToString();

                //Thread[] threads = new Thread[totalCount];
                //int threadId = 0, current = 0;

                // 进度条
                tsbarGenerate.Maximum = totalCount;
                tsbarGenerate.Step = 1;

                DateTime dtStart = DateTime.Now;
                DateTime dtEnd;

                #region 单线程

                // 单线程
                //foreach (string tableName in cklstTables.CheckedItems)
                //{
                //    try
                //    {
                //        GenerateCode(m_TargetPath, m_TemplatePath, m_Template, m_OutputFile, tableName);
                //    }
                //    catch (Exception ex)
                //    {
                //        continue;
                //    }
                //}

                //dtEnd = DateTime.Now;
                //MessageHelper.ShowInfomation("提示", "生成成功！");
                //MessageHelper.ShowInfomation("提示", "共耗时 " + (dtEnd - dtStart).TotalMilliseconds + "ms");

                #endregion

                // 多线程
                for (int i = 0; i < totalCount; )
                {
                    // 线程池
                    string target = cklstTables.CheckedItems[i++].ToString();
                    ThreadPool.QueueUserWorkItem(GenerateStart, target);

                    #region 线程数组
                    //threads[threadId] = new Thread(delegate()
                    //{

                    //    try
                    //    {
                    //        GenerateCode(targetPath, templatePath, template, outputFile, target);
                    //        current++;
                    //        //lock (tsslblCurrent.Text)
                    //        //{
                    //        //    current++;
                    //        //    tsbarGenerate.Value = current;
                    //        //    tsslblCurrent.Text = current.ToString();
                    //        //}
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        Console.WriteLine(ex.Message);
                    //    }
                    //});
                    //threads[threadId].Start();
                    //threadId++;
                    #endregion
                }

                Thread threadCount = null;
                threadCount = new Thread(delegate()
                {
                    while (true)
                    {
                        tsbarGenerate.Value = m_CurrentCount;
                        tsslblCurrent.Text = m_CurrentCount.ToString();

                        #region 统计线程数组
                        //bool IsStop = true;
                        //foreach (Thread thread in threads)
                        //{
                        //    if (thread != null && thread.IsAlive)
                        //    {
                        //        IsStop = false;
                        //    }
                        //}
                        #endregion

                        // 统计线程池的可用线程数量
                        int workedCount = 0, idleCount = 0;
                        ThreadPool.GetAvailableThreads(out workedCount, out idleCount);
                        if (workedCount == MAX_WORKED_THREADS)
                        {
                            dtEnd = DateTime.Now;

                            tsbarGenerate.Value = m_CurrentCount;
                            tsslblCurrent.Text = m_CurrentCount.ToString();

                            tsslblStatus.Text = "生成成功";
                            tsslblStatus.ForeColor = Color.Green;

                            TimeSpan span = (dtEnd - dtStart);
                            string time = String.Format("{0}时{1}分{2}秒{3}毫秒",
                                span.Hours, span.Minutes, span.Seconds, span.Milliseconds);

                            if (sbError.Length == 0)
                            {
                                // 全部生成成功
                                MessageHelper.ShowInfomation("提示", "生成成功！\n共耗时 " + time);
                            }
                            else
                            {
                                using (TextWriter writer = new StreamWriter(m_TargetPath + "\\Error.log"))
                                {
                                    writer.WriteLine(sbError.ToString());
                                    writer.Flush();
                                    writer.Close();
                                }
                                DialogResult result =
                                    MessageHelper.ShowQuestion("提示", "部分生成失败！\n共耗时 " + time + "\n日志：" + m_TargetPath + "\\Error.log" + "\n现在要查看错误信息吗？");
                                if (result == DialogResult.Yes)
                                {
                                    Process.Start(m_TargetPath + "\\Error.log");
                                }
                            }

                            // 生成后打开文件夹
                            if (ckAutoOpen.Checked)
                            {
                                Process.Start(m_TargetPath);
                            }

                            threadCount.Abort();
                        }
                    }
                });
                threadCount.Start();
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }

        }

        /// <summary>
        /// 启动生成
        /// </summary>
        /// <param name="target"></param>
        void GenerateStart(object target)
        {
            GenerateCode(m_TargetPath, m_TemplatePath, m_Template, m_OutputFile, target.ToString());
        }


        /// <summary>
        /// 生成文件
        /// </summary>
        /// <param name="targetPath">目标路径</param>
        /// <param name="templatePath">模板路径</param>
        /// <param name="outputFile">输出文件模板</param>
        /// <param name="tableName">表名</param>
        private void GenerateCode(string targetPath, string templatePath,
            ITemplate template, IFile outputFile, string tableName)
        {
            try
            {
                if (dicTables.ContainsKey(tableName))
                {
                    TableModal table = dicTables[tableName];
                    table.Columns = opSchema.GetColumns(table.DatabaseName, table.TableName);
                    string fileName = null;
                    string result = template.ExecuteTempldate(templatePath, table, out fileName);
                    if (fileName == null || fileName.Trim().Length == 0)
                    {
                        return;
                    }
                    outputFile.OutputFile(result, targetPath,
                        fileName.Replace(Environment.NewLine, String.Empty));
                    m_CurrentCount++;
                }
            }
            catch (Exception ex)
            {
                lock (sbError)
                {
                    sbError.AppendLine("错误：生成表【" + tableName + "】出错");
                    sbError.AppendLine("时间：" + DateTime.Now.ToString());
                    sbError.AppendLine(ex.Message);
                    sbError.AppendLine(ex.StackTrace);
                }
            }
        }

        /// <summary>
        /// 全选或全不选表名
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lbtnSelectedTables_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            try
            {
                if (cklstTables.Items.Count == 0)
                {
                    return;
                }

                LinkLabel lbtn = sender as LinkLabel;
                bool result = Boolean.Parse(lbtn.Tag.ToString());
                for (int i = 0; i < cklstTables.Items.Count; i++)
                {
                    cklstTables.SetItemChecked(i, result);
                }
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        /// <summary>
        /// 显示插件管理窗体
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbtnPlugIns_Click(object sender, EventArgs e)
        {
            try
            {
                Form frm = new PlugInsForm();
                frm.ShowDialog();
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        private void tsbtnAbout_Click(object sender, EventArgs e)
        {
            try
            {
                Form frm = new AboutForm();
                frm.ShowDialog();
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        /// <summary>
        /// 选择语言
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void radLanguage_CheckedChanged(object sender, EventArgs e)
        {
            try
            {
                if (sender is RadioButton)
                {
                    RadioButton rad = sender as RadioButton;
                    m_Language = rad.Tag.ToString();
                    // 加载模板
                    cboTemplates.DataSource = null;
                    cboTemplates.Items.Clear();
                    if (!TemplateFiles.Files.ContainsKey(m_Language))
                    {
                        return;
                    }
                    IList<TemplateFileModal> lstTemplates = TemplateFiles.Files[m_Language];
                    cboTemplates.DataSource = lstTemplates;
                    cboTemplates.DisplayMember = "TemplateName";
                    cboTemplates.ValueMember = "FilePath";
                }
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }
        }

        /// <summary>
        /// 设置模板的输出文件类型
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboTemplates_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                string templateName = cboTemplates.Text.Trim();
                if (templateName == null)
                {
                    return;
                }
                TemplateFileModal templateFile = null;
                IList<TemplateFileModal> files = TemplateFiles.Files[m_Language];
                foreach (TemplateFileModal file in files)
                {
                    if (file.TemplateName == templateName)
                    {
                        templateFile = file;
                        break;
                    }
                }
                if (templateFile == null)
                {
                    return;
                }
                cboOutputFileExt.SelectedValue = templateFile.Output;
            }
            catch (Exception ex)
            {
                MessageHelper.ShowError("错误", ex.Message);
            }

        }
    }
}
